﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Serialization;
using AliCMS;
using AliCMS.SystemModule;

namespace WxPayApi
{
    public class PrepareParam : Page
    {
		protected string Params = "{}";

		public PrepareParam(string pathInTemplate) : base(pathInTemplate)
        {
        }

		/*
		** （1）需传递的参数有：PaymentType（必填。支付类型），ID（必填。订单ID，一般包含在地址），Amount（必填。支付金额，单位为元），NotifyUrl（必填。异步通知网址），PaymentID（必填。支付ID）
		**/
		protected override void OnLoad(EventArgs e)
		{
			string paymentType = Request.QueryString["PaymentType"];
			if (paymentType != "WEIXIN_PAY_BY_WAP")
				return;

			string orderId = Request.QueryString["ID"];
			if (String.IsNullOrEmpty(orderId))
			{
				Manager.Log("SystemModule - WxPayApi - PrepareParam - OnLoad - 1", "必须正确指定参数：ID", PageLang);
				/*
				File.AppendAllText(Server.MapPath("~/log.txt"), @"\r\n==========================  微信支付  =================================\r\n
																	日期：" + DateTime.Now + "\r\n" + "必须正确指定参数：ID" +
																 "\r\n=======================================================================\r\n");
				*/
				Response.Write("必须正确指定参数：ID");
				return;
			}

			if (String.IsNullOrEmpty(Request.QueryString["Amount"]) || !Regex.IsMatch(Request.QueryString["Amount"], @"^\d+(\.\d+)?$"))
			{
				Manager.Log("SystemModule - WxPayApi - PrepareParam - OnLoad - 1", "必须正确指定参数：Amount", PageLang);
				/*
				File.AppendAllText(Server.MapPath("~/log.txt"), @"\r\n==========================  微信支付  =================================\r\n
																	日期：" + DateTime.Now + "\r\n" + "必须正确指定参数：Amount" +
																 "\r\n=======================================================================\r\n");
				*/
				Response.Write("必须正确指定参数：Amount");
				return;
			}

			#region 通过PaymentId获取支付配置信息
			Dictionary<string, string> config = new Dictionary<string, string>();
			config["NotifyUrl"] = Request.QueryString["NotifyUrl"];
			if (!String.IsNullOrEmpty(Request.QueryString["DynamicSiteID"]))//如果是子网站
			{
				DataRow companyInstance = Manager.Channels.Select(AliCMS.SystemModule.Alias.Module.Namespace + "='AliCMS.CompanyModule'")[0];
				using (IDbObject paymentBll = (IDbObject)Manager.CreateObject("Payment", (int)companyInstance[Alias.Instance.InnerID], PageLang, false))
				{
					Dictionary<string, object> payment = paymentBll.Get(new Guid(Request.QueryString["PaymentID"]));

					DataRow paymentObject = Manager.Objects.Select(Alias.Module.Object.Namespace + "='AliCMS.CompanyModule' and " + Alias.Module.Object.Name + "='Payment'")[0];
					string accountNameField = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + paymentObject[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='AccountName'")[0][Alias.Module.Object.Property.UniqueInnerID].ToString();
					string accountField = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + paymentObject[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='Account'")[0][Alias.Module.Object.Property.UniqueInnerID].ToString();
					string partnerIdField = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + paymentObject[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='PartnerID'")[0][Alias.Module.Object.Property.UniqueInnerID].ToString();
					string keyField = Manager.Properties.Select(Alias.Module.Object.Property.ObjectID + "='" + paymentObject[Alias.Module.Object.ID] + "' and " + Alias.Module.Object.Property.Name + "='Key'")[0][Alias.Module.Object.Property.UniqueInnerID].ToString();

					config["APPID"] = payment[accountNameField].ToString();
					config["APPSECRET"] = payment[accountField].ToString();
					config["MCHID"] = payment[partnerIdField].ToString();
					config["KEY"] = payment[keyField].ToString();
				}
			}
			else//如果是独立网站
			{
				using (IPayment paymentBll = (IPayment)Manager.CreateObject("Payment", 0, PageLang, false))
				{
					Dictionary<string, object> payment = paymentBll.Get(new Guid(Request.QueryString["PaymentID"]));

					config["APPID"] = payment[Alias.Payment.AccountName].ToString();
					config["APPSECRET"] = payment[Alias.Payment.Account].ToString();
					config["MCHID"] = payment[Alias.Payment.PartnerID].ToString();
					config["KEY"] = payment[Alias.Payment.Key].ToString();
				}
			}
			#endregion

			if (String.IsNullOrEmpty(Request.QueryString["code"]))
			{
				#region 获取code
				string returnUrl = Request.Headers["X-Original-URL"];
				if (String.IsNullOrEmpty(returnUrl))
					returnUrl = Request.Url.ToString();
				String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + config["APPID"] + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl) + "&response_type=code&scope=snsapi_base&state=" + orderId + "#wechat_redirect";
				Response.Redirect(url);
				#endregion
			}
			else
			{
				PayData data = null;
				HttpWebRequest request = null;
				HttpWebResponse response = null;
				StreamReader sr = null;
				string result = null;

				try
				{
					#region 获取openId
					//准备数据
					data = new PayData(config);
					data.SetValue("appid", config["APPID"]);
					data.SetValue("secret", config["APPSECRET"]);
					data.SetValue("code", Request.QueryString["code"]);
					data.SetValue("grant_type", "authorization_code");

					//请求Url
					string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();
					request = (HttpWebRequest)WebRequest.Create(url);
					response = (HttpWebResponse)request.GetResponse();
					sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
					result = sr.ReadToEnd().Trim();
					sr.Close();

					//转换成json
					JavaScriptSerializer serializer = new JavaScriptSerializer();
					Dictionary<string, object> jsonObject = serializer.DeserializeObject(result) as Dictionary<string, object>;

					//获取openId
					string openId = jsonObject["openid"].ToString();
					#endregion

					#region 统一下单
					//准备数据
					data.Clear();
					data.SetValue("body", Request.QueryString["Title"]);
					data.SetValue("out_trade_no", orderId.Replace("-", ""));
					data.SetValue("total_fee", Convert.ToInt32(Convert.ToDecimal(Request.QueryString["Amount"]) * 100));
					data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
					//data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
					data.SetValue("trade_type", "JSAPI");
					data.SetValue("openid", openId);
					data.SetValue("notify_url", config["NotifyUrl"]);
					data.SetValue("appid", config["APPID"]);
					data.SetValue("mch_id", config["MCHID"]);
					data.SetValue("spbill_create_ip", Request.UserHostAddress);
					data.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));
					data.SetValue("sign", data.MakeSign());
					result = data.ToXml();

					//请求Url
					url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
					request = (HttpWebRequest)WebRequest.Create(url);
					request.Method = "POST";
					request.Timeout = 6 * 1000;
					request.ContentType = "text/xml";
					byte[] buffer = System.Text.Encoding.UTF8.GetBytes(result);
					request.ContentLength = buffer.Length;

					//往服务器写入数据
					Stream reqStream = request.GetRequestStream();
					reqStream.Write(buffer, 0, buffer.Length);
					reqStream.Close();

					//获取服务端返回
					response = (HttpWebResponse)request.GetResponse();
					sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
					result = sr.ReadToEnd().Trim();
					sr.Close();

					//统一订单数据
					data.Clear();
					data.FromXml(result);

					//生成支付参数
					if (Convert.ToString(data.GetValue("return_code")) == "SUCCESS")
					{
						PayData jsApiParam = new PayData(config);
						jsApiParam.SetValue("appId", data.GetValue("appid"));
						jsApiParam.SetValue("timeStamp", GenerateTimeStamp());
						jsApiParam.SetValue("nonceStr", Guid.NewGuid().ToString().Replace("-", ""));
						jsApiParam.SetValue("package", "prepay_id=" + data.GetValue("prepay_id"));
						jsApiParam.SetValue("signType", "MD5");
						jsApiParam.SetValue("paySign", jsApiParam.MakeSign());

						Params = jsApiParam.ToJson();
					}
					else
					{
						Manager.Log("SystemModule - WxPayApi - PrepareParam - OnLoad - 生成支付参数 - 1", result, PageLang);
						/*
						File.AppendAllText(Server.MapPath("~/log.txt"), @"\r\n==========================  微信支付  =================================\r\n
																	日期：" + DateTime.Now + "\r\n" + result +
																		 "\r\n=======================================================================\r\n");
						*/
						Response.Write("发生错误，请与管理员联系！");
					}
					#endregion
				}
				catch (Exception exp)
				{
					Manager.Log("SystemModule - WxPayApi - PrepareParam - OnLoad - 生成支付参数 - 2", exp.ToString() + "\r\nresult:" + result, PageLang);
					/*
					File.AppendAllText(Server.MapPath("~/log.txt"), @"\r\n==========================  微信支付  =================================\r\n
																	日期：" + DateTime.Now + "\r\n" + exp.ToString() +
																	 "\r\n=======================================================================\r\n");
					*/
					Response.Write("发生错误，请与管理员联系！");
				}
			}
		}


		/**
		* 生成时间戳，标准北京时间，时区为东八区，自1970年1月1日 0点0分0秒以来的秒数
		 * @return 时间戳
		*/
		public static string GenerateTimeStamp()
		{
			TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
			return Convert.ToInt64(ts.TotalSeconds).ToString();
		}
	}
}
